home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / msg / msg2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-11  |  16.1 KB  |  877 lines

  1. /*
  2.  *            M S G 2 . C
  3.  *
  4.  * This is the second part of the MSG program.
  5.  *
  6.  * Functions -
  7.  *    rdnxtfld    read next field from input
  8.  *    prhdr        print header on stdout
  9.  *    hdrfile        print header on outfp
  10.  *    hdrout        print header on specified FILE p
  11.  *    gomsg        goto a specific message
  12.  *    delmsg        delete specified message
  13.  *    undelmsg    un-delete specified message
  14.  *    keepmsg        mark specified message for keeping
  15.  *    getfn        
  16.  *    cpyiter
  17.  *    cppipe
  18.  *    cpopen
  19.  *    dolstmsg    list the selected messages, maybe separated
  20.  *    lstmsg        list one message, maybe separated
  21.  *    lstbdy        list body of one message
  22.  *    movmsg        "move" a message
  23.  *    putmsg        "put" a message
  24.  *    writmsg        write specified message onto given FD
  25.  *    writbdy        write body of specified message onto given FD
  26.  *    prmsg        print specified message onto terminal
  27.  *    ansiter        top-level iteration for "answer"
  28.  *    ansqry        enquire who to send answer to
  29.  *    ansmsg        create header for answer
  30.  *    fwditer        top-level iteration for "forward"
  31.  *    fwdmsg        copy one forwarded message, with markers
  32.  *    fwdpost        add trailer to forwarded message
  33.  *    srchkey        Keyword search for stripping obnoxious header lines.
  34.  *    filout        Filters control characters before writing on terminal.
  35.  *    makedrft    Make a file containing one or more messages
  36.  *
  37.  *        R E V I S I O N   H I S T O R Y
  38.  *
  39.  *    06/08/82  MJM    Split the enormous MSG program into pieces.
  40.  *
  41.  *    09/10/82  MJM    Modified to use STDIO for output to files, too.
  42.  *
  43.  *    11/14/82  HW    Added keyword filter to ignore Via, Remailed, etc.
  44.  */
  45. #include "util.h"
  46. #include "mmdf.h"
  47. #include <pwd.h>
  48. #include <signal.h>
  49. #include <sys/stat.h>
  50. #include <sgtty.h>
  51. #include "./msg.h"
  52.  
  53. extern FILE *popen();
  54.  
  55. /*
  56.  *            R D N X T F L D
  57.  *
  58.  * read next field from input
  59.  */
  60. rdnxtfld()
  61. {
  62.     register char   c;
  63.  
  64.     do  {
  65.         c = ttychar();
  66.     }  while( (isspace( c) || c == ch_erase) && c != '\n' );
  67.  
  68.     return(c);
  69. }
  70.  
  71. /*
  72.  *            P R H D R
  73.  */
  74. prhdr()
  75. {
  76.     hdrout( stdout, TRUE);
  77. }
  78.  
  79. /*
  80.  *            H D R F I L E
  81.  */
  82. hdrfile()
  83. {
  84.     hdrout( outfp, FALSE);
  85. }
  86.  
  87.  
  88.  
  89.  
  90. hdrout( fp,crflag)
  91. FILE *fp;
  92. int crflag;
  93. {
  94.     char lbuf[LINESIZE];
  95.  
  96.     sprintf( lbuf, "%4d%c%c%c%c%c%c%5ld: %-9.9s %-15.15s %.30s%s\n",
  97.         msgno,
  98.         mptr->flags & M_NEW ? 'N' : ' ',
  99.         mptr->flags & M_DELETED ? 'D' : ' ',
  100.         mptr->flags & M_KEEP ? 'K' : ' ',
  101.         mptr->flags & M_ANSWERED ? 'A' : ' ',
  102.         mptr->flags & M_FORWARDED ? 'F' : ' ',
  103.         mptr->flags & M_PUT ? 'P' : ' ',
  104.         mptr->len,
  105.         mptr->datestr,
  106.         mptr->from,
  107.         mptr->subject,
  108.         crflag ? "\r" : ""
  109.     );
  110.     filout( lbuf, fp );
  111. }
  112.  
  113. /*--------------------------------------------------------------------*/
  114.  
  115. gomsg()
  116. {
  117.     status.ms_curmsg = msgno;          /* set the current message number     */
  118. }
  119.  
  120. delmsg()
  121. {
  122.     mptr->flags |= M_DELETED;
  123.     mptr->flags &= ~M_KEEP;
  124. }
  125.  
  126. undelmsg()
  127. {
  128.     mptr->flags &= ~(M_DELETED|M_KEEP);
  129. }
  130.  
  131. keepmsg()
  132. {
  133.     mptr->flags |= M_KEEP;
  134.     mptr->flags &= ~M_DELETED;
  135. }
  136.  
  137. /*
  138.  *            G E T F N
  139.  *
  140.  * Get a file name for the user.
  141.  */
  142. getfn( s, f, def)
  143. char    *s;        /* Prompt string to provoke user */
  144. char    *f;        /* place to put resulting answer */
  145. char    *def;        /* optional default */
  146. {
  147.     char    tmpbuf[LINESIZE];
  148.     char    name[LINESIZE];
  149.     struct passwd *getpwuid(), *getpwnam();
  150.     register char *t, *n;
  151.     register struct passwd *pw;
  152.  
  153.     tt_norm();
  154.     fputs( s, stdout);
  155.     fflush( stdout);
  156.  
  157.     strcpy( oldfile, f);
  158.  
  159.     if( gets( tmpbuf) == NULL || isnull( tmpbuf[0]))  {
  160.         if( def == (char *)0)
  161.             error( "no filename specified\r\n");
  162.         else  {
  163.             strcpy( f, def);
  164.             printf( "%s...\r\n", f);
  165.         }
  166.     }  else  {
  167.         /* Remove leading whitespace */
  168.         for( t = tmpbuf; isspace(*t); t++ )
  169.             ;
  170.         if( *t == '~' ) {
  171.             /* Expand */
  172.             for( n = name; *++t && *t != '/'; *n++ = *t )
  173.                 ;
  174.             *n = '\0';
  175.             if( name[0] == '\0' )
  176.                 pw = getpwuid(getuid());
  177.             else
  178.                 pw = getpwnam(name);
  179.             if( pw == NULL )
  180.                 error("~name not found\r\n");
  181.             (void) strcpy(f, pw->pw_dir);
  182.             (void) strcat(f, t);
  183.         } else
  184.             strcpy(f, t);
  185.     }
  186.  
  187.     nxtchar = '\n';          /* note the last character typed      */
  188.     tt_raw();
  189. }
  190.  
  191. /*
  192.  *            C P Y I T E R
  193.  */
  194. cpyiter( fn, iterfl, post)
  195. int    ( *fn)();        /* per-message function               */
  196. int    iterfl;            /* To iterate or not to iterate          */
  197. int    ( *post)();        /* post-process function              */
  198. {
  199.     if( outfile[0] == '|')        /* output filter, not file */
  200.         cppipe();        /* get the output pipe */
  201.     else
  202.         cpopen();        /* get the output file */
  203.  
  204.     tt_norm();
  205.     if( iterfl == DOIT )
  206.         doiter( fn);
  207.     else
  208.         (*fn)();
  209.     tt_norm();
  210.  
  211.     if(post != 0)
  212.         (*post)();
  213.  
  214.     if(outfile[0] == '|') {    /* collect the child */
  215.         pclose( outfp );    /* done sending to file/pipe */
  216.         signal( SIGINT, onint );
  217.     } else
  218.         lk_fclose (outfp, outfile, NULL, NULL);
  219.  
  220.     outfd = -1;
  221.     tt_raw();
  222. }
  223.  
  224. /*
  225.  *            C P P I P E
  226.  */
  227. cppipe()
  228. {
  229.     char    buf[LINESIZE];
  230.  
  231.     fflush(stdout);
  232.     if ((outfp = popen(&outfile[1], "w")) == NULL)
  233.         error( "problem starting pipe command\r\n");
  234.  
  235.     outfd = -1;
  236.     return;
  237. }
  238.  
  239. /*
  240.  *            C P O P E N
  241.  *
  242.  * open a file to copy into
  243.  */
  244. cpopen()
  245. {
  246.  
  247.     /* EXCLUSIVE open the file, as we are writing */
  248.     if( (outfd = lk_open( outfile, 1, (char *)0, (char *)0, 5)) < 0)  {
  249.         switch( errno)  {
  250.         case ENOENT:
  251.             if( !autoconfirm)  {
  252.                 printf( "Create '%s'", outfile);
  253.                 if( !confirm((char *)0,DOLF))
  254.                     error( "");
  255.             }
  256.             if( (outfd = creat( outfile, sentprotect)) < 0)  {
  257.                 printf( "can't create '%s'", outfile);
  258.                 error( "\r\n");
  259.             }
  260.  
  261.             close( outfd);
  262.             /* EXCLUSIVE open, since writing */
  263.             if( (outfd = lk_open( outfile, 1, (char *)0, (char *)0, 5)) < 0)  {
  264.                 printf( "can't open '%s'", outfile);
  265.                 error( "\r\n");
  266.             }
  267.             break;
  268.  
  269.         case ETXTBSY:
  270.             printf( "'%s' is busy; try later", outfile);
  271.             error( "\r\n");
  272.  
  273.         default:
  274.             perror(outfile);
  275.             error( "\r");
  276.         }
  277.     }
  278.  
  279.     /*
  280.      * Set up for STDIO output using the exclusive
  281.      * write-only FD.  The fclose( outfd ) will flush
  282.      * the buffers.  The "a" append is necessary in
  283.      * the event that the file already exists.
  284.      */
  285.     if( (outfp = fdopen( outfd, "a" )) == NULL ) {
  286.         error( "can't fdopen outfile\n" );
  287.         outfd = -1;
  288.     }
  289. }
  290.  
  291. /*
  292.  *            D O L S T M S G
  293.  *
  294.  * list the selected messages, maybe separated
  295.  */
  296. dolstmsg()
  297. {
  298.     doiter ( lstmsg);
  299. }
  300.  
  301. /*
  302.  *            L S T M S G
  303.  *
  304.  * list one message, maybe separated
  305.  */
  306. lstmsg()
  307. {
  308.     if( lstsep && lstmore)
  309.         fputs( "\f\n", outfp );
  310.     lstmore = TRUE;
  311.  
  312.     if( prettylist) {
  313.         fprintf(outfp, "(Message # %d: %ld bytes", msgno, mptr->len );
  314.         if( mptr->flags & M_DELETED )    fprintf(outfp, ", Deleted");
  315.         if( mptr->flags & M_PUT )    fprintf(outfp, ", Put");
  316.         if( mptr->flags & M_NEW )    fprintf(outfp, ", New");
  317.         if( mptr->flags & M_KEEP )    fprintf(outfp, ", KEEP");
  318.         if( mptr->flags & M_ANSWERED )    fprintf(outfp, ", Answered");
  319.         if( mptr->flags & M_FORWARDED )    fprintf(outfp, ", Forwarded");
  320.         fprintf(outfp, ")\n");
  321.     }
  322.         
  323.     writmsg();
  324.     mptr->flags &= ~M_NEW;        /* Message seen */
  325. }
  326.  
  327. /*
  328.  *            L S T B D Y
  329.  *
  330.  * list one message body, maybe separated
  331.  */
  332. lstbdy()
  333. {
  334.     if( lstsep && lstmore)
  335.         fputs( "\f\n", outfp );
  336.     lstmore = TRUE;
  337.  
  338.     writbdy();
  339.     mptr->flags &= ~M_NEW;        /* Message seen */
  340. }
  341.  
  342. /*
  343.  *            M O V M S G
  344.  */
  345. movmsg()
  346. {
  347.     putmsg();
  348.     delmsg();
  349. }
  350.  
  351. /*
  352.  *            P U T M S G
  353.  */
  354. putmsg()
  355. {
  356.     register int len;
  357.  
  358.     len = strlen( delim1);
  359.     fwrite( delim1, sizeof(char), len, outfp );
  360.     writmsg();
  361.     fwrite( delim2, sizeof(char), len, outfp );
  362.     mptr->flags |= M_PUT;
  363. }
  364.  
  365. /*
  366.  *            W R I T M S G
  367.  */
  368. writmsg()
  369. {
  370.     long size;
  371.     int count;
  372.     char tmpbuf[512];
  373.  
  374.     fseek( filefp,( long)( mptr->start), 0);
  375.     for( size = mptr->len; size > 0; size -= count)  {
  376.         if( size <( sizeof tmpbuf))
  377.             count = size;
  378.         else
  379.             count =( sizeof tmpbuf);
  380.  
  381.         if( fread( tmpbuf, sizeof( char), count, filefp) < count)
  382.             error( "error reading\r\n");
  383.         if( fwrite( tmpbuf, sizeof(char), count, outfp ) < count )
  384.             error( "error writing to file\r\n");
  385.     }
  386. }
  387.  
  388. /*
  389.  *            W R I T B D Y
  390.  */
  391. writbdy()
  392. {
  393.     long size;
  394.     int srcstat;
  395.     char line[LINESIZE];
  396.  
  397.     fseek( filefp,( long)( mptr->start), 0);
  398.     size = mptr->len;
  399.  
  400.     srcstat = SP_HNOSP;
  401.     while( size > 0)  {
  402.         if( xfgets( line, sizeof( line), filefp) == NULL )
  403.             break;
  404.         size -= strlen( line );
  405.  
  406.         if( srcstat == SP_HNOSP && *line == '\n' ) {
  407.             /* Don't output the separating blank line */
  408.             srcstat = SP_BODY;
  409.             continue;
  410.         }
  411.  
  412.         if( srcstat == SP_BODY )
  413.             fputs( line, outfp );
  414.  
  415.     }
  416. }
  417.  
  418. /*
  419.  *            P R M S G
  420.  */
  421. prmsg()
  422. {
  423.     char line[LINESIZE];
  424.     register long size;
  425.     int    srcstat;
  426.  
  427.     tt_norm();
  428.  
  429.     size = mptr->len;
  430.     status.ms_curmsg = msgno;
  431.  
  432.     printf( "(Message # %d: %ld bytes", msgno, size );
  433.     if( mptr->flags & M_DELETED )    printf(", Deleted");
  434.     if( mptr->flags & M_PUT )    printf(", Put");
  435.     if( mptr->flags & M_NEW )    printf(", New");
  436.     if( mptr->flags & M_KEEP )    printf(", KEEP");
  437.     if( mptr->flags & M_ANSWERED )    printf(", Answered");
  438.     if( mptr->flags & M_FORWARDED )    printf(", Forwarded");
  439.     printf(")\n");
  440.     fflush( stdout );
  441.  
  442.     if(quicknflag == ON )
  443.         mptr->flags &= ~M_NEW;        /* Message seen */
  444.  
  445.     fseek( filefp,( long)( mptr->start), 0);
  446.  
  447.     srcstat = SP_HNOSP;
  448.     while( size > 0)  {
  449.         if( xfgets( line, sizeof( line), filefp) == NULL )
  450.             break;
  451.  
  452.         if( *line == '\n' )
  453.             srcstat = SP_BODY;
  454.         /* filter obnoxious lines */
  455.         if( keystrip == ON && srcstat != SP_BODY ) {
  456.             if( !(srcstat == SP_HSP &&
  457.                 (*line == '\t' || *line == ' ')))
  458.                 if( srchkey( line, keywds) == 0 ) {
  459.                     filout( line, stdout );
  460.                     srcstat = SP_HNOSP;
  461.                 }
  462.                 else
  463.                     srcstat = SP_HSP;
  464.         }
  465.         else
  466.             filout( line, stdout);
  467.  
  468.         size -= strlen( line );
  469.     }
  470.     tt_raw();
  471.     mptr->flags &= ~M_NEW;        /* Message seen */
  472. }
  473.  
  474. /*--------------------------------------------------------------------*/
  475.  
  476. /*
  477.  *            A N S I T E R
  478.  *
  479.  * Top level for "answer" command.
  480.  */
  481. ansiter()
  482. {
  483.     sndto[0] =
  484.         sndcc[0] =
  485.         sndsubj[0] = '\0';
  486.     ansnum = 0;
  487.  
  488.     doiter( prhdr);
  489.     anstype = ansqry();
  490.  
  491.     doiter( ansmsg);
  492.  
  493.     if( ansnum == 0)
  494.         printf( "no messages to answer\r\n");
  495.     else
  496.         if( isnull( sndto[0]))
  497.             printf( "no From field in header\r\n");
  498.         else {
  499.             xeq( 'a');        /* execute an answer command */
  500.             doiter( ansend );    /* Set the A flag */
  501.         }
  502. }
  503.  
  504. /*
  505.  *            E D A N S I T E R
  506.  *
  507.  * Top level for "answer" command, to drop into EMACS 2-window mode.
  508.  */
  509. edansiter()
  510. {
  511.     register int fd;
  512.  
  513.     sndto[0] =
  514.         sndcc[0] =
  515.         sndsubj[0] = '\0';
  516.     ansnum = 0;
  517.  
  518.     doiter( prhdr);
  519.     anstype = ansqry();
  520.  
  521.     doiter( ansmsg);
  522.  
  523.     if( ansnum == 0)  {
  524.         printf( "no messages to answer\r\n");
  525.         return;
  526.     }
  527.     if( isnull( sndto[0]) )  {
  528.         printf( "no From field in header\r\n");
  529.         return;
  530.     }
  531.  
  532.     /* Prepare the work files */
  533.     if( (fd = creat(draft_work, sentprotect)) < 0 )  {
  534.         perror( draft_work );
  535.         return;
  536.     }
  537.     close(fd);
  538.  
  539.     makedrft();
  540.  
  541.     /* Invoke EDITOR in 2-window mode */
  542.     xeq( 'e' );
  543.  
  544.     /* Feed results into SEND */
  545.     xeq( 'A' );
  546.  
  547.     /* Set the A flag */
  548.     doiter( ansend );
  549.  
  550.     /* Clean up */
  551.     unlink( draft_original );
  552.     /* draft_work left behind in case he wants another look at it */
  553. }
  554.  
  555. /*
  556.  *            A N S Q R Y
  557.  * who to send answer to
  558.  */
  559. ansqry()
  560. {
  561.  
  562. again:
  563.     printf( "copies to which original addresses: ");
  564.     nxtchar = echochar();
  565.     nxtchar = uptolow( nxtchar);
  566.  
  567.     switch( nxtchar)  {
  568.  
  569.     case '\n':
  570.     case '\r':
  571.         if( verbose)
  572.             printf( "from\r\n");
  573.         return( ANSFROM);
  574.  
  575.     case 'a':
  576.         if( verbose)
  577.             printf( "ll\r\n");
  578.         return( ANSALL);
  579.  
  580.     case 'c':
  581.         if( verbose)
  582.             printf( "c'd\r\n");
  583.         return( ANSCC);
  584.  
  585.     case 'f':
  586.         if( verbose)
  587.             printf( "rom\r\n");
  588.         return( ANSFROM);
  589.  
  590.     case 't':
  591.         if( verbose)
  592.             printf( "o\r\n");
  593.         return( ANSTO);
  594.  
  595.     case '?':
  596.         if( verbose)
  597.             printf( "\r\n");
  598.         printf( "all\r\n");
  599.         printf( "cc'd\r\n");
  600.         printf( "from [default]\r\n");
  601.         printf( "to\r\n");
  602.         goto again;
  603.  
  604.     case '\004':
  605.     default:
  606.         error( " ?\r\n");
  607.     }
  608.     /* NOTREACHED */
  609. }
  610.  
  611.  
  612. /*
  613.  *            A N S M S G
  614.  *
  615.  * get create To, & Subject fields
  616.  */
  617. ansmsg()
  618. {
  619.     char tmpfrom[M_BSIZE],
  620.     tmprply[M_BSIZE],
  621.     tmpsender[M_BSIZE],
  622.     tmpto[M_BSIZE],
  623.     tmpcc[M_BSIZE],
  624.     tmpsubj[M_BSIZE];
  625.     register unsigned int ind;
  626.     int llenleft;
  627.  
  628.     ansnum++;
  629.     status.ms_curmsg = msgno;
  630.  
  631.     tmpfrom[0] =
  632.         tmprply[0] =
  633.         tmpsender[0] =
  634.         tmpto[0] =
  635.         tmpcc[0] =
  636.         tmpsubj[0] = '\0';
  637.  
  638.     gethead( NODATE, tmpfrom, tmpsender, tmprply,
  639.     (anstype & ANSTO) ? tmpto : NOTO,
  640.     (anstype & ANSCC) ? tmpcc : NOCC, tmpsubj);
  641.  
  642.     if( !isnull( tmprply[0]))
  643.         /* send to Reply-To */
  644.         sprintf( &sndto[strlen( sndto)], ",%s%c", tmprply, '\0');
  645.     else if( !isnull( tmpfrom[0]))
  646.         /* send to From, if no Reply-To */
  647.         sprintf( &sndto[strlen( sndto)], ",%s%c", tmpfrom, '\0');
  648.  
  649.     if( !isnull( tmpto[0]))
  650.         sprintf( &sndcc[strlen( sndcc)], ",%s%c", tmpto, '\0');
  651.  
  652.     if( !isnull( tmpcc[0]))
  653.         sprintf( &sndcc[strlen( sndcc)], ",%s%c", tmpcc, '\0');
  654.  
  655.     if( !isnull( tmpsubj[0]))  {
  656.         /* save the destination */
  657.         if( equal( "re:", tmpsubj, 3))
  658.             for( ind = 3; isspace( tmpsubj[ind]); ind++);
  659.         else
  660.             if( equal( "reply to:", tmpsubj, 9))
  661.                 for( ind = 9; isspace( tmpsubj[ind]); ind++);
  662.             else
  663.                 ind = 0;
  664.  
  665.         if( ansnum  == 1)
  666.             /* not the first message */
  667.             sprintf( sndsubj, "Re:  %s%c", &tmpsubj[ind], '\0');
  668.         else {
  669.             /* append more addresses */
  670.             if( (llenleft = sizeof(sndsubj) - strlen(sndsubj))
  671.                 -strlen(&tmpsubj[ind])-9 > 0 )
  672.                 sprintf( &sndsubj[strlen( sndsubj)],
  673.                     "\n     %s%c", &tmpsubj[ind], '\0');
  674.             else if( llenleft > 7 )
  675.                 sprintf( &sndsubj[strlen( sndsubj)],
  676.                 "\n...%c", '\0');
  677.         }
  678.     }
  679. }
  680. /*--------------------------------------------------------------------*/
  681. ansend() {        /* Set the A flag */
  682.  
  683.     mptr->flags |= M_ANSWERED;
  684. }
  685. /*--------------------------------------------------------------------*/
  686. /*
  687.  *            F W D I T E R
  688.  *
  689.  * Top level for forward command.
  690.  */
  691. fwditer()
  692. {
  693.     char *mktemp();
  694.  
  695.     status.ms_curmsg = msgno;
  696.     fwdnum = 0;
  697.     sndto[0] =
  698.         sndcc[0] =
  699.         sndsubj[0] = '\0';
  700.  
  701.     doiter( prhdr);
  702.  
  703.     strcpy( outfile, "/tmp/send.XXXXXX");
  704.     mktemp( outfile);
  705.  
  706.     autoconfirm = TRUE;
  707.     cpyiter( fwdmsg, DOIT, fwdpost);
  708.     autoconfirm = FALSE;
  709.  
  710.     xeq( 'f');
  711.     unlink( outfile);
  712. }
  713.  
  714. /*
  715.  *            F W D M S G
  716.  *
  717.  * copy one forwarded message
  718.  */
  719. fwdmsg()
  720. {
  721.     char line[M_BSIZE];
  722.     int    llenleft;
  723.     
  724.     fwdnum++;
  725.  
  726.     line[0] = '\0';        /* build a subject line */
  727.     gethead( NODATE, NOFROM, NOSNDR, NORPLY, NOTO, NOCC, line);
  728.  
  729.     if( !isnull( line[0]))  {
  730.         /* If we had a subject line, bracket the subject info */
  731.         if( isnull( sndsubj[0]) )
  732.             /* the first subject line */
  733.             sprintf( sndsubj, "[%s:  %s]%c",
  734.                 mptr->from, line, '\0');
  735.         else {
  736.             /* not the first line */
  737.             if( (llenleft = sizeof(sndsubj) - strlen(sndsubj))
  738.                 -strlen(line)-SIZEFROM-10 > 0 )
  739.                 sprintf( &sndsubj[strlen( sndsubj)],
  740.                 "\n[%s:  %s]%c", mptr->from, line, '\0');
  741.             else if( llenleft > 7 )
  742.                 sprintf( &sndsubj[strlen( sndsubj)],
  743.                 "\n...%c", '\0');
  744.  
  745.         }
  746.     }
  747.  
  748.     fprintf( outfp, "\n----- Forwarded message # %d:\n\n", fwdnum);
  749.  
  750.     writmsg();
  751.  
  752.     mptr->flags |= M_FORWARDED;
  753. }
  754.  
  755. /*
  756.  *            F W D P O S T
  757.  */
  758. fwdpost()
  759. {
  760.     fprintf( outfp, "\n----- End of forwarded messages\n" );
  761. }
  762. /*
  763.  *            S R C H K E Y
  764.  */
  765. srchkey( line, keypt)
  766.     char *line, *keypt[];
  767. {
  768.     register int    n;
  769.     register char    *pkey, *pline;
  770.  
  771.     for( n = 0; keypt[n] != 0; n++ ) {
  772.         pkey = keypt[n];
  773.         pline = line;
  774.  
  775.         while( *pkey != '\0' ) {
  776.  
  777.             if( *pline != *pkey && *pline - 'A' + 'a' != *pkey )
  778.                 goto trynext;
  779.             pline++;
  780.             pkey++;
  781.         }
  782.         return(1);
  783. trynext: ;
  784.     }
  785.     return(0);
  786. }
  787. /* ------------------------------------------------------------------ 
  788.  *            F I L O U T
  789.  *
  790.  *    Filter most control chars from text - Prevents letter bombs
  791.  *    Also does paging
  792.  *    ****** linecount must be initialized before calling filout ******
  793.  */
  794. filout(line, ofp)
  795.     char *line;
  796.     FILE *ofp;
  797. {
  798.     register int cmd;
  799.  
  800.     if( paging ) {
  801.         linecount += (strlen( line ) / linelength ) + 1;
  802.  
  803.         if( doctrlel && strindex( "\014", line) >= 0) {
  804.             /* Got formfeed */
  805.             tt_raw();
  806.             if( !confirm("Formfeed. Continue?",NOLF))
  807.                 error("");
  808.             tt_norm();
  809.             linecount = 0;
  810.         }
  811.  
  812.         if ( linecount >= pagesize - 2) {
  813.             tt_raw();
  814.             if( (cmd = confirm("Continue?",NOLF)) == FALSE )
  815.                 error("");
  816.             tt_norm();
  817.             switch( cmd ) {
  818.  
  819.             case '\n':        /* One more line */
  820.                 linecount = pagesize;
  821.                 break;
  822.                 
  823.             default:
  824.                 linecount = 0;
  825.                 break;
  826.             }
  827.         }
  828.     }
  829.  
  830.     if( filoutflag == OFF ) {
  831.         fputs( line, ofp );
  832.         return;
  833.     }
  834.     
  835.     for( ; *line != '\000'; line++ ) {
  836.         if( *line >= ' ' && *line <= '~' )
  837.             putc( *line, ofp );
  838.         else {
  839.             switch ( *line ) {
  840.  
  841.             case '\007':    /* Bel */
  842.             case '\t':
  843.             case '\n':
  844.             case '\r':
  845.             case '\b':
  846.                 putc( *line, ofp );
  847.                 break;
  848.  
  849.             default:
  850.                 putc( '^', ofp );
  851.                 putc( *line + '@', ofp );
  852.                 break;
  853.             }
  854.         }
  855.     }
  856. }
  857. /*
  858.  *              M A K E D R F T
  859.  *  Make a file containing one or more messages
  860.  */
  861. makedrft() {
  862.  
  863.     register int fd;
  864.  
  865.     if( (fd = creat(draft_original, sentprotect)) < 0 )  {
  866.         perror( draft_original );
  867.         return;
  868.     }
  869.     close( fd );
  870.  
  871.     /* LIST messages into the draft_original file */
  872.     lstsep = TRUE;
  873.     strcpy( outfile, draft_original );
  874.     cpyiter( lstmsg, DOIT, (int(*)()) 0 );
  875.  
  876. }
  877.